package com.hp.bon.sgw.ctrl;

import java.io.File;
import java.io.IOException;
import java.util.Map;

import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.factory.annotation.Autowired;

import com.hp.bon.sgw.bean.SysPertriNetBean;
import com.hp.bon.sgw.ctrl.SGWController.NodeProcessInf;
import com.hp.bon.sgw.threads.SGWDataStoreWatchDog;

/**
 * 定期巡视所有SGW 节点进程以及节点状态
 * 
 * @author wuzhih
 * 
 */
public class SGWProcessWatchDog {

	/**
	 * Logger for this class
	 */
  private static final Logger logger = LoggerFactory.getLogger(SGWProcessWatchDog.class);
  private PetriExecutor pertriExecutor;
  private SGWDataStoreWatchDog dataStoreWatchDog;
  private int checkPeriod = 30;

  private long prevCheckedTime = System.currentTimeMillis() + 10000L;

  public void setCheckPeriod(int checkPeriod) {
    this.checkPeriod = checkPeriod;
    if (checkPeriod <= 0) {
      checkPeriod = 60;
    }
    logger.info("check system process period " + checkPeriod);
  }

	public void doShutdownCheck() {
		// 检查状态切换结果
		int petriStatus = pertriExecutor.getPertriBean().getStatus();
		if (petriStatus == SysPertriNetBean.PETRI_STATUS_PREPARE_MAITAIN || petriStatus == SysPertriNetBean.PETRI_STATUS_PREPARE_OFFLINE) {
			boolean hasNodeAlive = false;
			String aliveNode = null;
			for (SGWController.NodeProcessInf nodeProc : ControllerConfigService.getInstance().getSgwInstanceMap().values()) {
				int status = pertriExecutor.checkNodeStatus(nodeProc, false);
				if (status != SysPertriNetBean.PETRI_STATUS_OFFLINE) {// 还有节点活着
					hasNodeAlive = true;
					aliveNode = nodeProc.toString();
					break;
				}
			}
			if (!hasNodeAlive) {
				logger.info("all nodes status is offline ,so change system's status ");
				if (petriStatus == SysPertriNetBean.PETRI_STATUS_PREPARE_MAITAIN) {
					pertriExecutor.getPertriBean().setNewStatus(SysPertriNetBean.PETRI_STATUS_MAINTAIN);
				} else {// offline ,so shutdown
					pertriExecutor.getPertriBean().setNewStatus(SysPertriNetBean.PETRI_STATUS_OFFLINE);
					try {
						Thread.sleep(5 * 1000);
						logger.info("flush datastore ....");
						dataStoreWatchDog.doWork();
					} catch (Exception e) {
						logger.warn("err:" + e);
					}
					pertriExecutor.needStop = true;
					File statFile = new File(pertriExecutor.getStatusFile());
					if (!statFile.exists()) {
						try {
							statFile.createNewFile();
						} catch (IOException e) {
							logger.warn("create shutdown status file err " + e);
						}
					}
				}
			} else {
				logger.warn(" still businiss process alive:" + aliveNode);

			}
		}
	}

	public void checkNodeStatus() {
		if (checkPeriod * 1000 + prevCheckedTime > System.currentTimeMillis()) {
			return;
		}

		if (!pertriExecutor.getPertriBean().canAutoMonitorNodesNormal()) {
			return;
		}
		prevCheckedTime = System.currentTimeMillis();

		Map<String, NodeProcessInf> newNodesMap = ControllerConfigService.getInstance().getSgwInstanceMap();
		// 重新装载所有节点
		Map<String, NodeProcessInf> processMap = ControllerConfigService.getInstance().getInstanceFormFile();

		if (!processMap.isEmpty()) {
			Map<String, NodeProcessInf> existsMap = ControllerConfigService.getInstance().getSgwInstanceMap();

			for (NodeProcessInf nodeProc : processMap.values()) {
				NodeProcessInf foundNode = existsMap.get(nodeProc.id);
				if (foundNode == null) {
					newNodesMap.put(nodeProc.id, nodeProc);
					logger.info("found new node to monitor: " + nodeProc.toString());
				}
			}
			ControllerConfigService.getInstance().setSgwInstanceMap(newNodesMap);
		}

		for (NodeProcessInf nodeProc : newNodesMap.values()) {
			int status = pertriExecutor.checkNodeStatus(nodeProc, false);

			if (status == SysPertriNetBean.PETRI_STATUS_OFFLINE) {
				// 节点进程死了，切换为故障
				pertriExecutor.getPertriBean().setErrorStatus();
        if ("SGW".equals(nodeProc.processType))
          logger.warn("msgprocesserror|" + nodeProc.id + "|" + SysPertriNetBean.getPertiStatusName(status));
        else if ("CTP".equals(nodeProc.processType))
          logger.warn("fileprocesserror|" + nodeProc.id + "|" + SysPertriNetBean.getPertiStatusName(status));
        else {
          logger.warn(nodeProc.id + "|" + SysPertriNetBean.getPertiStatusName(status));
        }

        String[] cmdPatterns = new String[1];
        cmdPatterns[0] = ("-DnodeID=" + nodeProc.id + " ");
        try {
          long[] pids = this.pertriExecutor.sysPlantform.checkProcessExists(cmdPatterns);
          if (pids[0] != 0L) continue;
          logger.warn("process [" + cmdPatterns[0] + "] not exists, try restart");
          this.pertriExecutor.sysPlantform.startProcess(this.pertriExecutor.getNodeStartCmd(nodeProc));
        }
        catch (Exception e) {
          logger.warn("check or restart [" + cmdPatterns[0] + "] exception" + e);
        }
      }
      else if (("SGW".equals(nodeProc.processType)) && 
        (status != -3) && (status != -4) && (status != -6) && (status != -1) && 
        (status != this.pertriExecutor.getPertriBean().getStatus())) {
        this.pertriExecutor.getPertriBean().setNewStatus(status);
      }
    }
  }

  @Autowired
  public void setPertriExecutor(PetriExecutor pertriExecutor)
  {
    this.pertriExecutor = pertriExecutor;
  }

  @Autowired
  public void setDataStoreWatchDog(SGWDataStoreWatchDog dataStoreWatchDog) {
    this.dataStoreWatchDog = dataStoreWatchDog;
  }
}